package br.com.android.math.fibonacci;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;

import android.app.Activity;
import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentUris;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import android.provider.MediaStore;
import android.util.Log;

/**
 * Uses the Contacts API to load contacts from the phonebook.
 */
public class ContactUtils
{
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
                                                      ContactsContract.Contacts._ID,
                                                      ContactsContract.Contacts.DISPLAY_NAME,
                                                      ContactsContract.Contacts.STARRED,
                                                      ContactsContract.Contacts.TIMES_CONTACTED,
                                                      ContactsContract.Contacts.CONTACT_PRESENCE,
                                                      ContactsContract.Contacts.PHOTO_ID,
                                                      ContactsContract.Contacts.LOOKUP_KEY,
                                                      ContactsContract.Contacts.HAS_PHONE_NUMBER,
                                                      };

    private Activity      context;

    static final int      CARD_LIMIT                  = 500;

    /**
     * Constructor
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param context Context of the running activity
     */
    public ContactUtils(Activity context)
    {
        super();
        this.context = context;
    }

    /**
     * Returns a list of all the contacts in the phonebook
     * 
     * @version 1.0
     * @since 2012-03-28
     * @return Returns a list of all the contacts in the phonebook
     */
    @SuppressWarnings("deprecation")
    public ArrayList<Relation> loadContacts()
    {
        String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) )";
//        String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " == 1))";
        Cursor c = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, select, null,
                ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
        context.startManagingCursor(c);

        ArrayList<Relation> cList = new ArrayList<Relation>();
        int a = 0;
        Relation relation;
        while (c.moveToNext() && a < CARD_LIMIT)
        {
            relation = new Relation();
            relation.setBook_id(new Integer(c.getString(0)).intValue());

            String[] name_splitted = c.getString(1).split(" ");
            relation.setFirstName(name_splitted[0]);
            if (name_splitted.length > 1)
                relation.setLastName(name_splitted[1]);

            ArrayList<String> numbers = getPhoneNumbers(c.getString(0));
            relation.setNumber(numbers.size() > 0 ? numbers.get(0) : "");

            relation.setConcept("Any");
            relation.setPhoto(loadContactPhoto(c) == null ? "android.resource://com.orange.rd.kramer/drawable/default_photo" : loadContactPhoto(c));

            cList.add(relation);
            a++;
        }
        c.close();
        return cList;
    }

    /**
     * Returns an uri pointing to the contact's photo
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param cursor Cursor on a specific contact
     * @return Returns an uri pointing to the contact's photo
     */
    private String loadContactPhoto(Cursor cursor)
    {
        if (cursor.getString(5) != null)
        {
            Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, cursor.getInt(0));
            return Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY).toString();
        }
        return null;
    }

    /**
     * Returns a list of all phone numbers that belong to the given contact
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param id Id of the given contact
     * @return Returns a list of all phone numbers that belong to the given contact
     */
    private ArrayList<String> getPhoneNumbers(String id)
    {
        ArrayList<String> phones = new ArrayList<String>();

        Cursor pCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
                new String[] { id }, null);
        while (pCur.moveToNext())
        {
            phones.add(pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
        }
        pCur.close();
        return (phones);
    }

    /**
     * Inserts the given relation into the stock phone book
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param r Relation to be added into the stock phone book
     */
    public void insert(Relation r)
    {
        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        int rawContactInsertIndex = ops.size();

        Builder builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI);
        builder.withValue(RawContacts.ACCOUNT_TYPE, null);
        builder.withValue(RawContacts.ACCOUNT_NAME, null);
        ops.add(builder.build());

        // Name
        builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
        builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex);
        builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
        builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, r.getFirstName().replace(" ", "-") + " " + r.getLastName().replace(" ", "-"));
        ops.add(builder.build());

        // Number
        builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
        builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex);
        builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
        builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, r.getNumber());
        builder.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
        ops.add(builder.build());

        // Picture
        try
        {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(r.getPhoto()));
            ByteArrayOutputStream image = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, image);
            builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
            builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex);
            builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
            builder.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, image.toByteArray());
            ops.add(builder.build());
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        // Add the new contact
        try
        {
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        String select = "(" + ContactsContract.Contacts.DISPLAY_NAME + " == \"" + r.getFirstName().replace(" ", "-") + " " + r.getLastName().replace(" ", "-") + "\" )";
        Cursor c = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, select, null,
                ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
        context.startManagingCursor(c);

        if (c.moveToNext())
        {
            r.setBook_id(new Integer(c.getString(0)).intValue());
        }
        else
        {
            r.setBook_id(-1);
        }
    }

    /**
     * Updates the given relation in the stock phone book
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param r Relation to be updated in the stock phone book
     */
    public void update(Relation r)
    {
        Log.e("", "" + r.getBook_id());
        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

        Builder builder = ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI);
        builder.withValue(RawContacts.ACCOUNT_TYPE, null);
        builder.withValue(RawContacts.ACCOUNT_NAME, null);
        ops.add(builder.build());

        // Name
        builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI);
        builder.withSelection(ContactsContract.Data._ID, new String[] { String.valueOf(r.getBook_id()) });
        builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
        builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, r.getFirstName().replace(" ", "-") + " " + r.getLastName().replace(" ", "-"));
        ops.add(builder.build());

        // Number
        builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI);
        builder.withSelection(ContactsContract.Data._ID, new String[] { String.valueOf(r.getBook_id()) });
        builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
        builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, r.getNumber());
        builder.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
        ops.add(builder.build());

        // Picture
        try
        {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(r.getPhoto()));
            ByteArrayOutputStream image = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, image);
            builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI);
            builder.withSelection(ContactsContract.Data._ID, new String[] { String.valueOf(r.getBook_id()) });
            builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
            builder.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, image.toByteArray());
            ops.add(builder.build());
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        // Update
        try
        {
            context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * Deletes the given relation from the stock phone book
     * 
     * @version 1.0
     * @since 2012-03-28
     * @param r Relation to be removed from the stock phone book
     */
    public void delete(Relation r)
    {
        Cursor pCur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
                new String[] { "" + r.getBook_id() }, null);
        while (pCur.moveToNext())
        {
            String lookupKey = pCur.getString(pCur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
            Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
            context.getContentResolver().delete(uri, null, null);
        }
    }
}
